package org.geekbang.time.commonmistakes.springpart1.aop_;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    private static final Logger logger = LoggerFactory.getLogger(MyService.class);

    @Autowired
    private AnotherService anotherService; // 我们要测试这个依赖是否为 null

    @Autowired
    private MyService self; // 【核心】自我注入Spring创建的代理对象

    /**
     * 错误的调用方式
     * 它直接调用一个private方法，这将绕过Spring AOP代理。
     */
    @Transactional // 添加@Transactional是为了确保Spring为此Service创建AOP代理
    public void executeWrongWay01() {
        logger.info("Executing the WRONG way... | this.aopNotWorkingWithPrivate()");
        // 使用 'this' 调用一个 private 方法, AOP不会生效
        this.aopNotWorkingWithPrivate();
    }


    /**
     * 错误的调用方式
     * 它直接调用一个private方法，这将绕过Spring AOP代理。
     */
    @Transactional // 添加@Transactional是为了确保Spring为此Service创建AOP代理
    public void executeWrongWay02() {
        logger.info("Executing the WRONG way... | self.aopNotWorkingWithPrivate()");
        // 使用 'self' 调用一个 private 方法, AOP不会生效
        // 它的 `anotherService` 字段可能未被注入, 导致NPE。
        self.aopNotWorkingWithPrivate();
    }

    /**
     * 正确的调用方式
     * 它通过自我注入的代理对象来调用一个public / protected方法。
     */
    @Transactional
    public void executeCorrectWay01() {
        logger.info("Executing the CORRECT way... | self.aopWorksWithPublic()");
        // 使用自我注入的代理 'self' 来调用 public 方法.
        // 这将确保调用通过Spring AOP代理，所有依赖都会被正确注入。
        self.aopWorksWithPublic();
    }

    /**
     * 正确的调用方式
     * 它通过自我注入的代理对象来调用一个public / protected方法。
     */
    @Transactional
    public void executeCorrectWay02() {
        logger.info("Executing the CORRECT way... | self.aopWorksWithProtected()");
        // 使用自我注入的代理 'self' 来调用 public 方法.
        // 这将确保调用通过Spring AOP代理，所有依赖都会被正确注入。
        self.aopWorksWithProtected();
    }

    /**
     * private方法：AOP无法拦截
     * 尝试通过 `this` 调用此方法时, `anotherService` 会是 null.
     */
    private void aopNotWorkingWithPrivate() {
        logger.info("Is anotherService null ? {}", (anotherService == null));
        anotherService.doSomething(); // 这行会抛出 NullPointerException
    }

    /**
     * public方法：AOP可以拦截
     * 必须通过代理对象(self)来调用才能确保AOP生效.
     */
    public void aopWorksWithPublic() {
        logger.info("Is anotherService null ? {}", (anotherService == null));
        anotherService.doSomething(); // 正常工作
        logger.info("AOP worked with public successfully!");
    }

    /**
     * protected 方法：AOP可以拦截
     * 必须通过代理对象(self)来调用才能确保AOP生效.
     */
    protected void aopWorksWithProtected() {
        logger.info("Is anotherService null ? {}", (anotherService == null));
        anotherService.doSomething(); // 正常工作
        logger.info("AOP worked with protected successfully!");
    }
}
